package driver

import (
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/sync/singleflight"
)

// memoryShard  Memory分片LRU缓存的双向链表结构
type memoryShard struct {
	cache        *MemoryCache            // 指向所属 Memory 缓存实例的指针
	maxSize      int64                   // 缓存分片最大容量，单位为字节
	totalSize    int64                   // 缓存分片当前数据大小，单位为字节
	totalCount   int64                   // 缓存分片当前缓存项的数量
	totalHits    int64                   // 缓存命中次数
	totalMisses  int64                   // 缓存未命中次数
	totalEvicts  int64                   // 缓存淘汰次数
	totalExpires int64                   // 缓存过期清理次数
	items        map[string]*memoryEntry // 缓存项的映射表，键为字符串类型
	head, tail   *memoryEntry            // 哨兵节点，用于快速访问链表的头部和尾部
	isEvicted    atomic.Bool             // 分片是否正处于淘汰进程中，用于并发控制淘汰逻辑的并发执行
	mu           sync.Mutex              // 互斥锁，用于并发控制缓存项的添加、删除和访问等操作
	sfGroup      singleflight.Group      // 单实例单飞 singleflight 实例，用于并发控制缓存项的加载和更新等操作
}

// newMemoryShard 创建新的 cacheShard 结构实例，用于缓存分片管理
func newMemoryShard(cache *MemoryCache) *memoryShard {
	head := &memoryEntry{}
	tail := &memoryEntry{}
	head.next = tail
	tail.prev = head
	return &memoryShard{
		cache:   cache,
		maxSize: cache.maxSize / int64(cache.cacheShardCount),
		items:   make(map[string]*memoryEntry, 128),
		head:    head,
		tail:    tail,
	}
}

// addToFront 将节点添加到头部，即最近使用过的位置
func (c *memoryShard) addToFront(node *memoryEntry) {
	if node != nil {
		node.next = c.head.next
		node.prev = c.head
		c.head.next.prev = node
		c.head.next = node
	}
}

// addToBack 将节点添加到尾部
func (c *memoryShard) addToBack(node *memoryEntry) {
	if node != nil {
		prev := c.tail.prev
		prev.next = node
		node.prev = prev
		node.next = c.tail
		c.tail.prev = node
	}
}

// moveToFront 将节点移动到链表头部（最近使用）
func (c *memoryShard) moveToFront(node *memoryEntry) {
	c.removeNode(node)
	c.addToFront(node)
}

// moveToBack 将节点移动到链表尾部（成为 LRU 候选）
func (c *memoryShard) moveToBack(node *memoryEntry) {
	c.removeNode(node)
	c.addToBack(node)
}

// resetNode 清理节点，避免内存泄漏和脏数据
func (c *memoryShard) resetNode(node *memoryEntry) {
	if node != nil {
		// 归还到对象池中，以便复用
		node.Release()
	}
}
func (c *memoryShard) removeNode(node *memoryEntry) {
	if node != nil {
		node.prev.next = node.next
		node.next.prev = node.prev
	}
}

// evictExpired 淘汰过期的缓存项
//   - 由调用入口函数加锁以保障并发安全
func (c *memoryShard) evictExpired() {
	for _, node := range c.items {
		if node != nil && node.expiredMs > 0 && time.Now().UnixMilli() >= node.expiredMs {
			if node.isEvicted.CompareAndSwap(false, true) {
				c.removeNode(node)
				delete(c.items, node.key)
				atomic.AddInt64(&c.totalSize, int64(-node.size))
				atomic.AddInt64(&c.totalCount, -1)
				atomic.AddInt64(&c.totalExpires, 1)
				c.resetNode(node)
			}
		}
	}
}

// evictLRU 按 LRU 机制淘汰最少使用的缓存项
//   - 由调用入口函数加锁以保障并发安全
func (c *memoryShard) evictLRU() {
	// 如果空间仍不够, 按 LRU 机制删除最少使用的数据
	node := c.tail.prev
	for atomic.LoadInt64(&c.totalSize) > c.maxSize {
		if node == nil || node == c.head || node == c.tail {
			return
		}
		next := node.prev
		if node.isEvicted.CompareAndSwap(false, true) {
			c.removeNode(node)
			delete(c.items, node.key)
			atomic.AddInt64(&c.totalSize, int64(-node.size))
			atomic.AddInt64(&c.totalCount, -1)
			atomic.AddInt64(&c.totalEvicts, 1)
			c.resetNode(node)
		}
		node = next
	}
}

// Evict 异步淘汰缓存项入口
func (c *memoryShard) Evict() {
	if c.isEvicted.CompareAndSwap(false, true) {
		c.mu.Lock()
		defer c.mu.Unlock()
		defer c.isEvicted.Store(false)
		// 先淘汰过期项
		c.evictExpired()
		if atomic.LoadInt64(&c.totalSize) <= c.maxSize {
			return
		}
		// 再淘汰最少使用的项
		c.evictLRU()
	}
}

func (c *memoryShard) Clear() {
	c.mu.Lock()
	c.items = make(map[string]*memoryEntry)
	head := &memoryEntry{}
	tail := &memoryEntry{}
	head.next = tail
	tail.prev = head
	c.head = head
	c.tail = tail
	c.totalSize = 0
	c.totalCount = 0
	c.totalHits = 0
	c.totalMisses = 0
	c.totalEvicts = 0
	c.totalExpires = 0
	c.mu.Unlock()
}
